using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Xml;
using System.Xml.Serialization;
using System.Threading;
using System.Collections.Generic;

using Dashboard;
using Dashboard.Util;
using Dashboard.Engine;

namespace Dashboard.Engine.Transports
{
	public class TcpTransport : IComponent
	{
		private const int port = 5369;
		
		private bool running = false;
		private TcpListener listener = null;
		private Thread thread = null;
		
		private List<TcpConnectionHandler> handlers = new List<TcpConnectionHandler> ();
		
		public void Initialize ()
		{
			try {
				listener = new TcpListener (IPAddress.Loopback, port);
				listener.Start ();
			} catch (SocketException ex) {
				Engine.Log.Error ("Could not start TCP listener: {0}", ex.Message);
				throw;
			}

			thread = new Thread (new ThreadStart (Worker));
			thread.Start ();
		}
		
		public void Dispose ()
		{
			running = false;
			listener.Stop ();
		}

		private void Worker ()
		{
			running = true;
			
			while (running) {
				if (!listener.Pending ()) {
					Thread.Sleep (100);
					continue;
				}

				TcpClient client;
				
				try {
					// This will block for an incomming connection
					client = listener.AcceptTcpClient ();
				} catch (SocketException) {
					// If the listener is stopped while we
					// wait for a connection, a
					// SocketException is thrown.
					break;
				}
				
				if (client == null)
					continue;
				
				TcpConnectionHandler handler = new TcpConnectionHandler (client);
				handler.Start ();

				// FIXME: Keep track of running handlers
				// so that we can cancel them when we
				// get disposed.
				handlers.Add (handler);
			}
		}

		private class TcpConnectionHandler : XmlConnectionHandler
		{
			private bool running;
			private TcpClient client;

			public TcpConnectionHandler (TcpClient client)
			{
				this.client = client;
			}

			protected override Stream Stream {
				get { return client.GetStream (); }
			}

			protected override bool Closed {
				get { return (client == null || (client.Client.Poll (10, SelectMode.SelectRead)
								 && client.Client.Available == 0));
				}
			}

			public override void Close ()
			{
				if (client == null)
					return;
				
				client.Close ();
				client = null;
			}
		}

		public string Name
		{
			get { return "TcpTransport"; }
		}
		
		public string Description
		{
			get { return "Transports messages to and from the engine via TCP/IP"; }
		}
	}
}
